using System;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using Sustainalytics.ESG.Entities;
using Sustainalytics.Synchronization.Validation.Handlers.Common;
using Sustainalytics.Synchronization.Validation.Internals;
using Sustainalytics.Synchronization.Validation.Validators;

namespace Sustainalytics.Synchronization.Validation.Handlers.Comprehensive
{
    public class RPControversyIndicatorHandler : Handler<RPControversyIndicator, ComprehensiveCompanies>
    {
        public RPControversyIndicatorHandler(ComprehensiveCompanies comprehensiveCompanies, ValidationMongoCollection<RPControversyIndicator> collections, ComprehensiveValidator<RPControversyIndicator> validator)
            : base(comprehensiveCompanies, collections, validator)
        {
        }

        public override async Task ForEachElementsAsync(Action<ValidationResult> validationCallback)
        {
            if (Validator.HasAssignedRules)
            {
                await
                    ValidatedDataCollection.Aggregate()
                        .Match(Builders<RPControversyIndicator>.Filter.In(x=>x.CompanyId, CompaniesIds))
                        .Group(
                            new BsonDocument
                                {
                                    { "_id", "$CompanyId" },
                                    { "AnswerCategory", new BsonDocument("$max", "$AnswerCategory") }
                                })
                        .ForEachAsync(
                            async bsonDocument =>
                                {
                                    var validatedEntity = BsonSerializer.Deserialize<RPControversyIndicator>(bsonDocument);

                                    var referenceEntity = await GetReferenceElementAsync(validatedEntity).ConfigureAwait(false);

                                    if (referenceEntity != null)
                                    {
                                        var validationResult = await Validator.ValidateAsync(validatedEntity, referenceEntity).ConfigureAwait(false);

                                        validationCallback(validationResult);
                                    }
                                }).ConfigureAwait(false);
            }
        }

        public override async Task<RPControversyIndicator> GetReferenceElementAsync(
            RPControversyIndicator validatedEntity)
        {
            var bsonDocument =
                await
                ReferenceDataCollection.Aggregate()
                    .Match(new BsonDocument { { "CompanyId", validatedEntity.Id } })
                    .Group(
                        new BsonDocument
                            {
                                { "_id", "$CompanyId" },
                                { "AnswerCategory", new BsonDocument("$max", "$AnswerCategory") }
                            })
                    
                    .FirstOrDefaultAsync().ConfigureAwait(false);

            return bsonDocument != null ? BsonSerializer.Deserialize<RPControversyIndicator>(bsonDocument) : null;
        }

        protected override ProjectionDefinition<RPControversyIndicator> GetProjectionDefinition()
        {
            return Builders<RPControversyIndicator>.Projection.Include(x => x.Id);
        }

        protected override FilterDefinition<RPControversyIndicator> GetReferenceEntityFilter(RPControversyIndicator validatedEntity)
        {
            return Builders<RPControversyIndicator>.Filter.Empty;
        }

        protected override FilterDefinition<RPControversyIndicator> GetValidatedEntityFilterDefinition(Guid companyId)
        {
            return Builders<RPControversyIndicator>.Filter.Where(x => x.Id == companyId);
        }
    }
}
